/*! \file scrollbar.cpp	
	This contains the implementation of the Scrollbar class
*/

#include "scrollbar.h"

Scrollbar::Scrollbar( Component* parent, int topID, int bottomID, int scrollID ) :
	topButtonID(topID),
	bottomButtonID(bottomID),
	scrollbarID(scrollID),
	Container( parent ),
	draggingSlider(false),
	scrollUnit( 10 ),
	scrollPage( 50 ),
	upButtonHeld(false),
	downButtonHeld(false),
	lengthHeld(0)
{
	upButton = new ImageButton( this, topID, topID );
	downButton = new ImageButton( this, bottomID, bottomID );
	slider = new ImageButton( this, scrollID, 16 );
	slider->setStretchOnResize( true );
	
	//~ slider->setBorder( true );
	
	sliderPosition = 0;
	maxPosition = 0;
	
	int upButtonWidth, upButtonHeight;
	int downButtonWidth, downButtonHeight;
	int sliderButtonWidth, sliderButtonHeight;
	ImageHandler::getInstance()->getImageSize( upButtonWidth, upButtonHeight, topButtonID );
	ImageHandler::getInstance()->getImageSize( downButtonWidth, downButtonHeight, bottomButtonID );
	ImageHandler::getInstance()->getImageSize( sliderButtonWidth, sliderButtonHeight, scrollbarID );
	w = upButtonWidth;
	
	addListener( this );
}

void Scrollbar::setSize( int newW, int newH ) {
	h = newH;
	
	// Always set the upButton to the highest possible position
	upButton->setPosition( 0, borderWidth );
	
	// Find the downButton's height and set the downButton's position to the lowest possible position
	int downButtonWidth, downButtonHeight;
	ImageHandler::getInstance()->getImageSize( downButtonWidth, downButtonHeight, bottomButtonID );
	downButton->setPosition( 0, h - borderWidth - downButtonHeight );
	
	// topMost is where the track begins in pixels from the top of the scrollbar
	topMost = borderWidth + upButton->getHeight();
	trackSize = h - borderWidth * 2 - upButton->getHeight() - downButton->getHeight();
	
	updateScroll();
}

void Scrollbar::setHeight( int newH ) {
	setSize( w, newH );
}

void Scrollbar::setWidth( int newW ) {
	cout << "Scrollbar::setWidth was called, except you can't change the width of a scrollbar" << endl;
	setSize( newW, h );
}

void Scrollbar::update() {
	// If either of the scrolling buttons are held down for long enough, then scroll
	if ( ( upButtonHeld || downButtonHeld ) && lengthHeld++ >= 20 ) {
		lengthHeld = 0;
		if ( upButtonHeld ) {
			sliderPosition -= scrollUnit;
			updateScroll();
		}
		if ( downButtonHeld ) {
			sliderPosition += scrollUnit;
			updateScroll();
		}
	}
}
	
void Scrollbar::mouseDown(Event e) {
	int mX, mY;
	glfwGetMousePos( &mX, &mY );
	mX -= getScreenX(); // if this is a top-level container, then its parent will be GUI, whose X is 0, so no change
	mY -= getScreenY();
	int sliderPixel = getScreenCoordOfSliderPosition();
	//~ cout << "mY: " << mY << " topMost + sliderPosition " << topMost + sliderPixel << " height: " << slider->getHeight() << endl;
	//~ cout << "MX: " << mX << " w " << w << endl;
	if ( mX >= 0 && mX < w ) {
		if ( mY > topMost + sliderPixel && mY < topMost + sliderPixel + slider->getHeight() ) {
			// slider button clicked
			draggingSlider = true;
			dragX = mX - x;
			dragY = mY - (sliderPixel + topMost);
			//~ cout << "DragY: " << dragY << endl;
			//~ draggedFrom = mY - topMost;
			cout << "Sliderposition " << sliderPosition << " Height: " << slider->getHeight() << endl;
			draggedFrom = topMost + getScreenCoordOfSliderPosition();
			cout << "DRAGGING SLIDER " << draggedFrom << endl;
			//~ draggedFrom = 54;
		} else if ( mY > borderWidth && mY < topMost ) {
			// up button clicked
			sliderPosition -= scrollUnit;
			updateScroll();
			upButtonHeld = true;
			lengthHeld = -100;
		} else if ( mY < h - downButton->getHeight() - borderWidth ) {
			// bar area clicked
			
			scrollToPixel( mY );
		} else if ( mY < h - borderWidth ) {
			// down button clicked
			sliderPosition += scrollUnit;
			updateScroll();
			downButtonHeld = true;
			lengthHeld = -100;
		}
	}
}

void Scrollbar::mouseUp(Event e) {
	draggingSlider = false;
	upButtonHeld = false;
	downButtonHeld = false;
}

void Scrollbar::onScroll( Event e ) {
	cout << glfwGetMouseWheel() << endl;
}
void Scrollbar::onEnter(Event e) {
}

void Scrollbar::onLeave(Event e) {
}

void Scrollbar::mouseMove( Event e ) {
	int mX, mY;
	glfwGetMousePos( &mX, &mY );
	mY -= getScreenY();
	mY = mY - (dragY);
	if ( draggingSlider ) {
		// If you're dragging the bar horizontally (perpendicular to scroll direction)
		// and you drag it too far away, then it will snap back to wherever you started dragging it
		if ( mX < getScreenX() - SCREENW / 4 || mX > getScreenX() + w + SCREENW / 4 ) {
			scrollToPixel( draggedFrom );
		} else {
			scrollToPixel( mY );
		}
	}
}

void Scrollbar::scrollToPixel( int pixelY ) {
	// NOTE: topMost is the lowest possible value that this could be, but if it's lower
	// then it will get snapped to the top anyway
	int screenCoord = pixelY - topMost;
	
	// convert to the sliderPosition now by using the ratio
	sliderPosition = (int)((float)screenCoord * maxPosition / ( trackSize - slider->getHeight()));
	//~ cout << "Percentage: " << (float)screenCoord / trackSize<< endl;
	//~ cout << "mY: " << screenCoord << " sliderPosition " << sliderPosition << " height: " << slider->getHeight() << endl;

	updateScroll();
	
}

void Scrollbar::updateScroll() {
	//~ cout << sliderPosition << endl;
	// This condition comes first because maxPosition can be less than 0
	if ( sliderPosition > maxPosition ) {
		sliderPosition = maxPosition;
	}
	if ( sliderPosition < 0 ) {
		sliderPosition = 0;
	}
	//~ cout << "Scrollbar::updateScroll ";
	//~ cout << " Slider: " << sliderPosition << " max: " << maxPosition << " trackSize " << trackSize << endl;
	slider->setPosition( 0, topMost + getScreenCoordOfSliderPosition() );
}
	
	
void Scrollbar::scrollToBottom() {
	sliderPosition = maxPosition;
	updateScroll();
}

int Scrollbar::getTrackSize() {
	return trackSize;
}

void Scrollbar::setMaxPosition( int newPosition ) {
	maxPosition = newPosition; 
}
	
int Scrollbar::getMaxPosition() {
	return maxPosition;
}
	
ImageButton* Scrollbar::getSlider() { 
	return slider; 
}

void Scrollbar::scrollByUnits( int numUnits ) {
	sliderPosition -= scrollUnit * numUnits;
	updateScroll();
}

int Scrollbar::getSliderPosition() {
	return sliderPosition;
}

void Scrollbar::setScrollUnit( int su ) {
	scrollUnit = su;
}
	
void Scrollbar::setScrollPage( int sp ) {
	scrollPage = sp;
}
	
int Scrollbar::getScrollUnit() {
	return scrollUnit;
}
	
int Scrollbar::getScrollPage() {
	return scrollPage;
}

void Scrollbar::draw() {
	glPushMatrix();
	glLoadIdentity();
	int screenX = getScreenX(), screenY = getScreenY();
	glTranslatef( (float)screenX, (float)screenY, 0.0 );
	Container::draw();
	glPopMatrix();
}
